package com.geeguo.ebuilder.core.security.utils;

import com.geeguo.ebuilder.core.common.utils.StringHelper;
import com.geeguo.ebuilder.core.security.annotation.Logical;
import com.geeguo.ebuilder.core.security.annotation.RequiresPermissions;
import com.geeguo.ebuilder.core.security.annotation.RequiresRoles;
import com.geeguo.ebuilder.core.security.constants.SecurityConstants;
import com.geeguo.ebuilder.core.security.exception.NotLoginException;
import com.geeguo.ebuilder.core.security.exception.NotPermissionException;
import com.geeguo.ebuilder.core.security.exception.NotRoleException;
import com.geeguo.ebuilder.core.security.exception.SessionOverdueException;
import com.geeguo.ebuilder.core.security.model.BaseLoginUser;
import com.geeguo.ebuilder.core.security.service.TokenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.PatternMatchUtils;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 权限验证逻辑实现类
 */
public class AuthHelper<T extends BaseLoginUser> {

    private final TokenService<T> tokenService;

    public AuthHelper(Class<T> loginUserType) {
        tokenService = new TokenService<>(loginUserType);
    }

    /**
     * 创建令牌并缓存
     */
    public void createToken(T loginUser) {
        tokenService.createToken(loginUser);
    }

    /**
     * 获取当前用户登录信息
     */
    public T getLoginUser() {
        String token = TokenHelper.getToken();
        if (StringUtils.isNotEmpty(token)) {
            return getLoginUser(token);
        }
        return null;
    }

    /**
     * 获取当前用户登录信息
     */
    public T getLoginUser(String token) {
        return tokenService.getLoginUser(token);
    }
    
    /**
     * 会话注销
     */
    public void logout() {
        String token = TokenHelper.getToken();
        if (StringUtils.isNotEmpty(token)) {
            logout(token);
        }
    }

    /**
     * 会话注销
     */
    public void logout(String token) {
        tokenService.removeLoginUser(token);
    }

    /**
     * 验证当前用户登录有效期
     */
    public void verifyExpireTime(T loginUser) {
        tokenService.verifyExpireTime(loginUser);
    }

    /**
     * 检验当前会话是否已经登录，如未登录，则抛出异常
     */
    public T checkLogin() {
        String token = TokenHelper.getToken();
        if (StringUtils.isEmpty(token)) {
            throw new NotLoginException("未提供Token");
        }
        T loginUser = getLoginUser(token);
        if (loginUser == null) {
            throw new SessionOverdueException("登录过期");
        }
        return loginUser;
    }
    
    /**
     * 根据注解(@RequiresRoles)鉴权, 如果验证未通过，则抛出异常: NotRoleException
     */
    public void checkRole(RequiresRoles requiresRoles) {
        if (requiresRoles.logical() == Logical.AND) {
            checkRoleAnd(requiresRoles.value());
        } else {
            checkRoleOr(requiresRoles.value());
        }
    }
    
    /**
     * 验证用户是否含有指定角色，必须全部拥有
     */
    public void checkRoleAnd(String... roles) {
        Set<String> userRoles = getUserRoles();
        for (String role : roles) {
            if (!hasRole(userRoles, role)) {
                throw new NotRoleException(role);
            }
        }
    }
    
    /**
     * 验证用户是否含有指定角色，只需包含其中一个
     */
    public void checkRoleOr(String... roles) {
        Set<String> userRoles = getUserRoles();
        for (String role : roles) {
            if (hasRole(userRoles, role)) {
                return;
            }
        }
        if (roles.length > 0) {
            throw new NotRoleException(roles);
        }
    }
    
    /**
     * 获取当前账号的角色列表
     */
    public Set<String> getUserRoles() {
        BaseLoginUser loginUser = checkLogin();
        return loginUser.getRoles() == null? new HashSet<>() : loginUser.getRoles();
    }
    
    /**
     * 判断是否包含角色
     */
    public boolean hasRole(Collection<String> userRoles, String role) {
        return userRoles.stream().filter(StringHelper::hasText).anyMatch(x -> SecurityConstants.SUPER_ADMIN_ROLE_CODE.equals(x) || PatternMatchUtils.simpleMatch(x, role));
    }

    /**
     * 根据注解(@RequiresPermissions)鉴权, 如果验证未通过，则抛出异常: NotPermissionException
     */
    public void checkPermission(RequiresPermissions requiresPermissions) {
        if (requiresPermissions.logical() == Logical.AND) {
            checkPermissionAnd(requiresPermissions.value());
        } else {
            checkPermissionOr(requiresPermissions.value());
        }
    }

    /**
     * 验证用户是否含有指定权限，必须全部拥有
     */
    public void checkPermissionAnd(String... permissions) {
        Set<String> userPermissions = getUserPermissions();
        for (String permission : permissions) {
            if (!hasPermission(userPermissions, permission)) {
                throw new NotPermissionException(permission);
            }
        }
    }

    /**
     * 验证用户是否含有指定权限，只需包含其中一个
     */
    public void checkPermissionOr(String... permissions) {
        Set<String> userPermissions = getUserPermissions();
        for (String permission : permissions) {
            if (hasPermission(userPermissions, permission)) {
                return;
            }
        }
        if (permissions.length > 0) {
            throw new NotPermissionException(permissions);
        }
    }

    /**
     * 获取当前账号的权限列表
     */
    public Set<String> getUserPermissions() {
        T loginUser = checkLogin();
        return loginUser.getPermissions() == null? new HashSet<>() : loginUser.getPermissions();
    }
    
    /**
     * 判断是否包含权限
     */
    public boolean hasPermission(Collection<String> userPermissions, String permission) {
        return userPermissions.stream().filter(StringHelper::hasText).anyMatch(x -> PatternMatchUtils.simpleMatch(x, permission));
    }
}